import characterTools from "shared/component/common/characterTools";
import { AABB, CollisionDetector } from "shared/component/common/collision2D";
import common from "shared/component/common/common";
import rMath from "shared/component/common/rMath";
import { ContainerService } from "shared/component/container/ContainerService";
import EventBinder from "shared/component/event/EventBinder";
import InstanceMap from "shared/component/event/InstanceRemoveEvent";
import { hotConfig } from "shared/component/hotconfig/hotconfig";
import Log4R from "shared/component/log/Log4R";
import { resource } from "shared/component/resource/resource";
import FrameManager from "shared/component/time/FrameManager";
import PauseTimer from "shared/component/time/PauseTimer";
import { AirState, CharacterState } from "shared/enums/CharacterState";
import { EffectEnum } from "shared/enums/EffectEnum";
import { SkillEnum } from "shared/enums/SkillEnum";
const loginfo = Log4R.getLog('info');
const testSkill: Ctn.skill.SkillConfig = {
    id: SkillEnum.testSkill,
    anim: "twohandSlash",
    moveType: 'A',
    stopFrame: 30,
    characterState: {
        setAirStates: AirState.none,
        life: {
            duration: 35 / 30,
            autoTransfrom: [
                {
                    airStates: AirState.Air,
                    targetStates: CharacterState.FreeFalling,
                }
            ]
        }
    },
    states: [
        {
            trigger: (input) => {
                return input.currentFrame === 0
            },
            turnCtrl: true,
        },
        {
            trigger: (input) => {
                return input.currentFrame === 2
            },
            turnCtrl: false,
        },

        {
            trigger: (input) => {
                return input.currentFrame === 3
                    && input.characterEntity?.humanStates?.airStates === AirState.Air
            },
            veloSet: {
                enable: true,
                // vector: new Vector3(0, 0, -50)
                line: -10
            }
        },
        {
            trigger: (input) => {
                return input.currentFrame === 8
                    && input.characterEntity?.humanStates?.airStates === AirState.Ground
            },
            veloSet: {
                enable: true,
                // vector: new Vector3(0, 0, -50)
                line: -10
            }
        },
        {
            trigger: (input) => {
                return input.currentFrame === 7
            },
            animEffect: {
                followPartName: "Trail"
            }
        },
        {
            trigger: (input) => (input.currentFrame === 10),
            hitDef: {
                /** 火花相对于p2的X坐标偏移量，火花相对于p1的Y坐标偏移量 */
                sparkxy: [-0.5, 4],
                pausetime: 4,
                advFrame: 4,
                hitbox: [0.43, 1.57, 6.14, 2.46],
                g: {
                    frame: 3,
                    line: 4
                },
                a: {
                    frame: 5,
                    line: 30
                }
            }
        },
        {
            trigger: (input) => (input.currentFrame === 14),
            veloSet: {
                enable: false,
            }
        },

        {
            trigger: (input) => (input.currentFrame === 20),
            cancelEnable: {
                [SkillEnum.testSkill]: {
                    enable: true
                }
            }
        },
        // {
        //     trigger: (input) => (input.currentFrame === 30),
        //     stoped: true
        // },
        // {
        //     trigger: (input) => {
        //         return input.currentFrame === 0 && input.characterEntity?.humanStates?.airStates !== AirState.Ground
        //     },
        //     moveCtrl: true,
        //     turnCtrl: true,
        // }
    ]
}

export class SkillServiceImpl extends ContainerService<Ctn.SkillService, Ctn.SkillEntity> implements Ctn.SkillService {
    /**
     * 移动控制器
     */
    private moveController?: Ctn.skill.MoveController;
    skills = new Map<number, Ctn.skill.SkillConfig>();
    /** 设置移动控制器 */
    setController(moveController: Ctn.skill.MoveController) {
        this.moveController = moveController
    }
    protected serverCalls: (keyof this)[] = [];
    protected serviceName: keyof Ctn.Services = "skillService";
    // private charachterSkillMap = new InstanceMap<Model, Ctn.skill.CharacterState>()
    /** 技能开始结束事件 */
    private skillEventBinder = new EventBinder<(skillInputEntity: Ctn.skill.SkillEntity) => void>();

    onSkill = this.skillEventBinder.bind();
    /** 暂停事件发生器 */
    private pauseEventBinder = new EventBinder<(
        /** 角色 */
        characterEntity: Ctn.character.CharacterEntity,
        /** pause状态 */
        pauseEntity: TimeComponent.PauseEntity,
    ) => void>();
    /** 技能暂停事件 */
    onPause = this.pauseEventBinder.bind();
    /** step事件发生器 */
    private stepEventBinder = new EventBinder<(
        /** 角色 */
        characterEntity: Ctn.character.CharacterEntity,
        /** pause状态 */
        input: Ctn.skill.SkillEntity,
    ) => void>();
    /** 技能步进 */
    onSkillStep = this.stepEventBinder.bind();
    /** 技能特效事件 */
    private effectEventBinider = new EventBinder<(
        /** 角色 */
        characterEntity: Ctn.character.CharacterEntity,
        /** skill状态 */
        input: Ctn.skill.State,
    ) => void>();
    /** 技能特效事件 */
    onEffect = this.effectEventBinider.bind();
    /** 技能特效事件 */
    private animChangeEventBinider = new EventBinder<(
        /** 角色 */
        characterEntity: Ctn.character.CharacterEntity,
        /** 动画名称 */
        anim: string,
    ) => void>();
    /** 动画改变事件 */
    onAnimChange = this.animChangeEventBinider.bind();
    /** 技能打击事件绑定器 */
    private hitEventBinder = new EventBinder<(
        /** 角色 */
        characterEntity: Ctn.character.CharacterEntity,
        /** skill状态 */
        input: Ctn.skill.State,
    ) => void>();
    /** 技能打击事件 */
    onHit = this.hitEventBinder.bind();
    /** 技能打击事件绑定器 */
    private animEventBinder = new EventBinder<(
        /** 角色 */
        characterEntity: Ctn.character.CharacterEntity,
        /** skill状态 */
        input: Ctn.skill.State,
    ) => void>();
    /** 技能动画事件 */
    onAnim = this.animEventBinder.bind();

    addCharacter(character: Model) {
        if (!character) return
        const characterEntity = this.getCharacter(character);
        if (!characterEntity?.character) return
        characterEntity.skillState = {
            character: characterEntity.character
        }
    }

    /** 获取state */
    private getState(character: Model) {
        const characterEntity = this.getCharacter(character);
        return characterEntity?.skillState

    }
    /** 处理需要结束的技能 */
    private beforeEndLastSkillState(currentSkill: Ctn.skill.SkillEntity) {
        const characterEntity = currentSkill.characterEntity

        currentSkill?.pauseTimer?.end();//结束暂停计时器
        currentSkill?.connection?.Disconnect();//结束计时
        currentSkill.character.HumanoidRootPart.skillVelocity.Enabled = false;
        if (characterEntity)
            characterTools.noCollisionUppertorso(characterEntity, false)
    }
    /** 使用技能 */
    skill(skillInputEntity: Ctn.skill.SkillEntity) {

        const characterEntity = this.getCharacter(skillInputEntity.character);
        if (!characterEntity?.character) return
        /** 技能配置 */
        const skill = skillInputEntity.skillConfig || this.skills.get(skillInputEntity.skillId) || testSkill;
        const state = this.getState(skillInputEntity.character);
        skillInputEntity.characterEntity = characterEntity
        if (state?.currentSkill && skill.moveType !== 'H') { //如果不是受到攻击的动作，检查当前动作是否已经完成
            if ((state?.currentSkill.currentFrame || 0) > 4) {//连击检测防抖动
                state.currentSkill.comboTry = skillInputEntity
            }
            //技能不可使用的条件： 技能期间不可控制 && 技能未结束 && （技能不可取消&&或者不能被要使用的技能取消）
            if (!state?.currentSkill?.skillConfig?.ctrl && !state?.currentSkill?.stoped
                && (!state?.currentSkill.cancelEnable || !state.currentSkill.cancelEnable[skill.id]?.enable)
            ) {
                return
            }
        }
        // if (!skill.ctrl) {
        //     state?.character.Humanoid.Move(new Vector3(0, 0, 0))
        // }
        //处理上一个技能的问题
        if (state?.currentSkill) {
            this.beforeEndLastSkillState(state.currentSkill)
        }

        if (!skillInputEntity.anim)
            skillInputEntity.anim = skill.anim //设置技能动画
        skillInputEntity.currentFrame = 0;
        skillInputEntity.skillConfig = skill;

        if (!state) throw ('no state')
        state.currentSkill = skillInputEntity
        this.skillEventBinder.callBack(skillInputEntity)
        /** 移动控制暂存 */
        let moveCtrl = false
        /** 转身控制暂存 */
        let turnCtrl = false

        // loginfo?.info('before connection', skillInputEntity)
        const connection = FrameManager.connect(h => {
            // loginfo?.info('deltaTimeSim', deltaTimeSim)
            // loginfo?.info('skillInputEntity.currentFrame', skillInputEntity.currentFrame
            //     , characterEntity.animTable?.currentAct[0].TimePosition
            //     , (characterEntity.animTable?.currentAct[0].TimePosition || 0) * 30
            // )
            if (h) return
            if (skillInputEntity.pauseTimer?.time()) {
                return
            }//卡肉计时器
            this.stepEventBinder.callBack(characterEntity, skillInputEntity);
            if (skill.stopFrame === skillInputEntity.currentFrame) {
                skillInputEntity.stoped = true
            }
            skill.states.forEach(state => {
                if (!characterEntity.character) return
                if (state.trigger(skillInputEntity)) {
                    if (state.stoped) {
                        skillInputEntity.stoped = state.stoped
                    }
                    if (state.cancelEnable) {
                        skillInputEntity.cancelEnable = {
                            ...skillInputEntity.cancelEnable,
                            ...state.cancelEnable
                        }
                        if (skillInputEntity.comboTry) {
                            this.skill(skillInputEntity.comboTry);
                        }
                    }
                    if (state.jump) {
                        skillInputEntity.character.Humanoid.Jump = true
                    }
                    if (state.moveCtrl !== undefined) {
                        if (state.moveCtrl !== moveCtrl) {
                            moveCtrl = state.moveCtrl
                            if (characterEntity.character) {
                                this.moveController?.setCtrlEnable(characterEntity.character, state.moveCtrl)
                            }

                        }

                    }
                    if (state.turnCtrl !== undefined) {
                        if (state.turnCtrl !== turnCtrl) {
                            turnCtrl = state.turnCtrl
                            if (characterEntity.character) {
                                this.moveController?.setTurnEnable(characterEntity.character, state.turnCtrl)
                            }

                        }

                    }
                    if (state.anim) {
                        if (state.anim.speed) {

                        }
                    }
                    if (state.rotate) {
                        const rotate = state.rotate
                        if (characterEntity.character) {
                            characterTools.rotateRoot(characterEntity.character, rotate.vector, rotate.life, rotate.angle, rotate.r)
                        }

                    }
                    if (state.veloSet) {
                        const velocity = skillInputEntity.character.HumanoidRootPart.skillVelocity;
                        velocity.Enabled = state.veloSet.enable;
                        if (state.veloSet.vector) {
                            velocity.RelativeTo = Enum.ActuatorRelativeTo.Attachment0
                            velocity.VelocityConstraintMode = Enum.VelocityConstraintMode.Vector
                            velocity.VectorVelocity = state.veloSet.vector || rMath.vectors.v0;
                        } else if (state.veloSet.line) {
                            velocity.RelativeTo = Enum.ActuatorRelativeTo.World
                            velocity.VelocityConstraintMode = Enum.VelocityConstraintMode.Line
                            // loginfo?.info('state.moveState?.vector', characterEntity.moveState?.orientation)
                            velocity.LineDirection = characterEntity.moveState?.orientation?.mul(-1) || rMath.vectors.right;
                            velocity.LineVelocity = state.veloSet.line
                        }
                        if (state.veloSet.ForceLimitsEnabled === undefined) {
                            velocity.ForceLimitsEnabled = true
                            velocity.MaxForce = 10000
                            // velocity.MaxForce = 1000
                        } else {
                            velocity.ForceLimitsEnabled = state.veloSet.ForceLimitsEnabled
                        }

                    }
                    if (!typeIs(state.noCollision, 'nil')) {
                        if (state.noCollision) {
                            characterTools.noCollisionUppertorso(characterEntity, state.noCollision)
                        }
                    }
                    if (state.animChage) {
                        this.animEventBinder.callBack(characterEntity, state)
                    }
                    if (state.hitDef) {
                        /** 攻击方向 */
                        const attackDirection = characterEntity.character.LowerTorso.CFrame.VectorToWorldSpace(rMath.vectors.front)
                        /** 击中 */
                        let hitSuccess = false
                        /** 打击定义 */
                        const hitDef = state.hitDef;
                        // loginfo?.info("characterMap", this.getInstanceMap())
                        /** 打 */
                        // const particalStartPart = characterEntity.character.FindFirstChild('RightWeapon') as BasePart | undefined;
                        if (hitDef.hitbox) {

                            const hitboxAABB = new AABB(...hitDef.hitbox);
                            this.getInstanceMap().forEach(targetCE => {
                                if (!characterEntity.character?.LowerTorso) return
                                if (targetCE.character && targetCE.character !== characterEntity.character) {
                                    // const orientation = characterEntity.character.HumanoidRootPart.AlignOrientation.CFrame.ToOrientation()
                                    const objectCframe = characterTools.getCharacterLogicCframe(characterEntity)
                                    if (!objectCframe) return
                                    const aabbOfTarget = AABB.genAABBByHumanModel(objectCframe, targetCE.character);
                                    const hitSuccessOfTarget = CollisionDetector.AABBCollision(hitboxAABB, aabbOfTarget)
                                    const recoverFrame = (skill.stopFrame - (skillInputEntity.currentFrame || 0))
                                        + hitDef.advFrame;
                                    // loginfo?.info("skillInputEntity.currentFrame", skillInputEntity.currentFrame)
                                    // loginfo?.info("recoverTime", recoverFrame)
                                    /** 目标空间的正向 */
                                    const frontInTargetSpace = targetCE.character.LowerTorso.CFrame.VectorToObjectSpace(attackDirection);
                                    /** -1为背面击中，1为正面击中 */
                                    let forceDirector = -1;
                                    if (frontInTargetSpace.Z > 0) {
                                        forceDirector = 1
                                    }
                                    if (hitSuccessOfTarget) {
                                        hitSuccess = true;
                                        /** 击退设定 */
                                        let backDef = hitDef.g
                                        if (hitDef.a && characterEntity?.humanStates?.airStates === AirState.Air) {
                                            backDef = hitDef.a
                                        }
                                        this.skill({
                                            skillId: SkillEnum.hit,
                                            character: targetCE.character,
                                            skillConfig: {
                                                stopFrame: recoverFrame,
                                                anim: "hit",
                                                moveType: "H",
                                                id: SkillEnum.hit,
                                                states: [
                                                    {
                                                        trigger: (input) => (input.currentFrame === 0),
                                                        pause: {
                                                            pausetime: hitDef.pausetime
                                                        },
                                                        rotate: {
                                                            vector: attackDirection,
                                                            life: hitDef.pausetime
                                                        },
                                                        veloSet: {
                                                            enable: true,
                                                            vector: backDef.vector?.mul(forceDirector),
                                                            line: (backDef.line || 0) * forceDirector
                                                        },
                                                        hitEffect: {
                                                            p1: characterEntity.character.LowerTorso,
                                                            p2: targetCE.character.LowerTorso,
                                                            effect: EffectEnum.SwordCut,
                                                            sparkxy: hitDef.sparkxy,
                                                            p1p2Direction: forceDirector
                                                            // particalStartPart
                                                        }
                                                    },
                                                    {
                                                        trigger: (input) => {
                                                            return input.currentFrame === backDef.frame;
                                                        },
                                                        veloSet: {
                                                            enable: false,
                                                        }
                                                    },
                                                    {
                                                        trigger: (input) => {
                                                            return input.currentFrame === 20;
                                                        },
                                                        anim: {
                                                            speed: 0
                                                        },
                                                    },
                                                    {
                                                        trigger: (input) => {
                                                            return input.currentFrame === (recoverFrame - 5);
                                                        },
                                                        anim: {
                                                            speed: 1
                                                        },
                                                    },
                                                ],
                                                characterState: {
                                                    setAirStates: AirState.none,
                                                    life: {
                                                        duration: recoverFrame / 30,
                                                        autoTransfrom: [
                                                            {
                                                                airStates: AirState.Air,
                                                                targetStates: CharacterState.FreeFalling,
                                                            }
                                                        ]
                                                    }
                                                },

                                            }
                                        })
                                    }

                                }
                            })
                        }

                        if (!hitSuccess) {
                            return
                        }
                        //处理卡肉停顿
                        skillInputEntity.pauseTimer?.end();//结束上一个卡肉
                        const pauseEntity: TimeComponent.PauseEntity = {
                            pause: true,
                            pauseedStrack: [],
                            currentFrame: skillInputEntity.currentFrame || 0
                        }
                        const pauseTimer = new PauseTimer(() => {
                            //广播暂停的结束事件
                            pauseEntity.pause = false
                            this.pauseEventBinder.callBack(characterEntity, pauseEntity)
                        }, hitDef.pausetime)
                        skillInputEntity.pauseTimer = pauseTimer
                        //广播暂停的开始事件
                        this.pauseEventBinder.callBack(characterEntity, pauseEntity)
                    }
                    if (state.pause) {
                        //处理卡肉停顿
                        skillInputEntity.pauseTimer?.end();//结束上一个卡肉
                        const pauseEntity: TimeComponent.PauseEntity = {
                            pause: true,
                            pauseedStrack: [],
                            currentFrame: skillInputEntity.currentFrame || 0
                        }
                        const pauseTimer = new PauseTimer(() => {
                            //广播暂停的结束事件
                            pauseEntity.pause = false
                            this.pauseEventBinder.callBack(characterEntity, pauseEntity)
                        }, state.pause.pausetime)
                        skillInputEntity.pauseTimer = pauseTimer
                        //广播暂停的开始事件
                        this.pauseEventBinder.callBack(characterEntity, pauseEntity)

                    }
                    if (state.animEffect || state.hitEffect) {
                        this.effectEventBinider.callBack(characterEntity, state)
                    }

                    // if (c.wait) {
                    //     task.wait(c.wait)
                    // }
                }
            });
            if (skillInputEntity.stoped) {
                this.beforeEndLastSkillState(skillInputEntity)

                this.skillEventBinder.callBack(skillInputEntity)
                return
            }
            (skillInputEntity.currentFrame as number)++

        })
        skillInputEntity.connection = connection

    }
    public init(): void {
        const skillsFolder = script.Parent?.Parent?.FindFirstChild('skills');
        if (skillsFolder?.IsA('Instance')) {
            hotConfig(skillsFolder, c => {
                // print("new", c)
                if (c.IsA('ModuleScript')) {
                    const skillConfig = require(c) as { default: Ctn.skill.SkillConfig };
                    if (skillConfig.default) {
                        loginfo?.info('skillConfig', skillConfig)
                        this.skills.set(skillConfig.default.id, skillConfig.default)
                    }

                }
            })
        } else {
            throw ('can not find skills folder')
        }
    }
}